#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
优化的WL文件脑电数据分割器

主要改进:
1. 完全基于配置文件驱动 - 消除硬编码
2. 使用ConfigManager进行配置管理
3. 改进的错误处理和日志记录
4. 更清晰的代码结构和文档
5. 支持可扩展的通道配置
"""

import os
import numpy as np
import csv
import wave
import struct
import json
import pickle
import logging
from typing import List, Dict, Any, Tuple, Optional
from pathlib import Path

# 导入配置管理器和原始wl_reader
from config_manager import ConfigManager, ChannelConfig
import wl_reader

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('wl_splitter.log', encoding='utf-8'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

class WLDataSplitter:
    """
    优化的WL数据分割器
    
    主要改进:
    - 完全配置文件驱动，无硬编码
    - 使用ConfigManager管理配置
    - 改进的错误处理
    - 更好的日志记录
    - 支持动态通道配置
    """
    
    def __init__(self, config_path: str = "config.json"):
        """
        初始化分割器
        
        Args:
            config_path: 配置文件路径
        """
        self.config_manager = ConfigManager(config_path)
        
        if not self.config_manager.validate_config():
            raise ValueError("配置验证失败，请检查配置文件")
        
        # 获取配置
        self.paradigm_type = self.config_manager.get_paradigm_type()
        self.file_config = self.config_manager.get_file_config()
        self.processing_config = self.config_manager.get_processing_config()
        self.channel_configs = self.config_manager.get_channel_configs()
        
        # 初始化数据属性
        self.wl_data = None
        self.fs = None
        self.dig_in_data = None
        self.amp_data = None
        self.time_stamps = None
        self.markers = []
        self.movement_data = None
        self.audio_data = None
        self.audio_fs = None
        self.audio_channels = None
        self.audio_sample_width = None
        
        logger.info(f"分割器初始化完成，使用配置文件: {config_path}")
        logger.info(f"启用通道数: {len([c for c in self.channel_configs.values() if c.enabled])}")
    
    def load_csv_data(self) -> bool:
        """
        根据配置的范式类型加载CSV文件数据
        
        Returns:
            bool: 是否成功加载
        """
        if not self.file_config.csv_path:
            logger.info("未配置CSV文件")
            return False
        
        csv_path = Path(self.file_config.csv_path)
        if not csv_path.exists():
            logger.warning(f"CSV文件不存在: {csv_path}")
            return False
        
        # 获取有效的范式类型
        effective_paradigm_type = self._get_effective_paradigm_type()
        
        try:
            data_list = []
            with open(csv_path, 'r', encoding='utf-8') as csvfile:
                reader = csv.DictReader(csvfile)
                headers = reader.fieldnames
                logger.info(f"检测到CSV列名: {headers}")
                logger.info(f"按{effective_paradigm_type}范式加载CSV数据")
                
                # 根据paradigm_type加载对应格式的数据
                if effective_paradigm_type == 'movement':
                    # 运动范式格式: order, stimuli, atext
                    required_cols = ['order', 'stimuli', 'atext']
                    if not all(col in headers for col in required_cols):
                        logger.error(f"运动范式CSV缺少必需列: {required_cols}")
                        logger.error(f"当前列名: {headers}")
                        return False
                    
                    for row in reader:
                        data_list.append({
                            'order': int(row['order']),
                            'stimuli': row['stimuli'],
                            'action': row['atext']
                        })
                    
                elif effective_paradigm_type == 'corpus':
                    # 语料范式格式: corpus_order, wl_corpus
                    required_cols = ['corpus_order', 'wl_corpus']
                    if not all(col in headers for col in required_cols):
                        logger.error(f"语料范式CSV缺少必需列: {required_cols}")
                        logger.error(f"当前列名: {headers}")
                        return False
                    
                    for row in reader:
                        data_list.append({
                            'order': int(row['corpus_order']),
                            'corpus': row['wl_corpus']
                        })
                    
                else:
                    logger.warning(f"范式类型为{effective_paradigm_type}，但提供了CSV文件，将忽略CSV数据")
                    return False
            
            # 排序并保存
            data_list.sort(key=lambda x: x['order'])
            self.movement_data = data_list  # 为兼容性保持变量名
            
            logger.info(f"成功加载{effective_paradigm_type}范式数据: {len(self.movement_data)}条")
            return True
            
        except Exception as e:
            logger.error(f"加载CSV文件失败: {e}")
            return False
    
    def load_audio_file(self) -> bool:
        """
        加载音频文件
        
        Returns:
            bool: 是否成功加载
        """
        if not self.file_config.audio_path:
            logger.info("未配置音频文件")
            return False
        
        audio_path = Path(self.file_config.audio_path)
        if not audio_path.exists():
            logger.warning(f"音频文件不存在: {audio_path}")
            return False
        
        try:
            logger.info(f"正在加载音频文件: {audio_path}")
            
            with wave.open(str(audio_path), 'rb') as wav_file:
                self.audio_channels = wav_file.getnchannels()
                self.audio_sample_width = wav_file.getsampwidth()
                self.audio_fs = wav_file.getframerate()
                n_frames = wav_file.getnframes()
                
                logger.info(f"音频参数: 通道={self.audio_channels}, 采样率={self.audio_fs}Hz, "
                           f"位深={self.audio_sample_width*8}bit, 时长={n_frames/self.audio_fs:.2f}s")
                
                # 读取音频数据
                raw_audio = wav_file.readframes(n_frames)
                
                # 转换为numpy数组
                dtype_map = {1: np.uint8, 2: np.int16, 4: np.int32}
                if self.audio_sample_width not in dtype_map:
                    raise ValueError(f"不支持的音频位深: {self.audio_sample_width*8}位")
                
                self.audio_data = np.frombuffer(raw_audio, dtype=dtype_map[self.audio_sample_width])
                
                if self.audio_channels > 1:
                    self.audio_data = self.audio_data.reshape(-1, self.audio_channels)
                
                logger.info(f"音频数据加载成功，形状: {self.audio_data.shape}")
                return True
                
        except Exception as e:
            logger.error(f"加载音频文件失败: {e}")
            return False

    def load_data_file(self) -> bool:
        """
        根据文件扩展名自动加载PKL或WL文件
        PKL文件应包含: marker, data, fs 字段
        WL文件通过wl_reader加载
        
        Returns:
            bool: 是否成功加载
        """
        data_path = self.file_config.data_path
        if not Path(data_path).exists():
            logger.error(f"数据文件不存在: {data_path}")
            return False
        
        file_ext = Path(data_path).suffix.lower()
        logger.info(f"正在加载{file_ext}文件: {data_path}")
        
        if file_ext == '.pkl':
            return self._load_pkl_file(data_path)
        elif file_ext == '.wl':
            return self._load_wl_file(data_path)
        else:
            logger.error(f"不支持的文件格式: {file_ext}")
            return False
    
    def _load_pkl_file(self, pkl_path: str) -> bool:
        """
        加载PKL文件数据
        PKL文件应包含: marker, data, fs 字段
        
        Args:
            pkl_path: PKL文件路径
            
        Returns:
            bool: 是否成功加载
        """
        try:
            with open(pkl_path, 'rb') as f:
                pkl_data = pickle.load(f)
            
            # 检查必需的字段
            required_fields = ['marker', 'data', 'fs']
            missing_fields = [field for field in required_fields if field not in pkl_data]
            if missing_fields:
                logger.error(f"PKL文件缺少必需字段: {missing_fields}")
                return False
            
            # 提取采样频率
            self.fs = pkl_data['fs']
            logger.info(f"采样频率: {self.fs} Hz")
            
            # 提取电生理数据
            self.amp_data = pkl_data['data']
            logger.info(f"电生理数据形状: {self.amp_data.shape}")
            
            # 提取数字输入数据（marker）
            self.dig_in_data = pkl_data['marker']
            logger.info(f"数字输入数据形状: {self.dig_in_data.shape}")
            
            # 生成时间戳
            num_samples = self.amp_data.shape[1] if len(self.amp_data.shape) > 1 else len(self.amp_data)
            self.time_stamps = np.arange(num_samples) / self.fs
            
            logger.info(f"PKL数据加载成功 - 数据长度: {len(self.time_stamps)} 样本点, "
                       f"时长: {len(self.time_stamps)/self.fs:.2f}秒")
            return True
            
        except Exception as e:
            logger.error(f"加载PKL文件失败: {e}")
            return False
    
    def _load_wl_file(self, wl_path: str) -> bool:
        """
        加载WL文件数据
        
        Args:
            wl_path: WL文件路径
            
        Returns:
            bool: 是否成功加载
        """
        try:
            self.wl_data, is_present = wl_reader.load_file(wl_path)
            
            if not is_present:
                logger.error("WL文件中没有数据")
                return False
            
            # 提取采样频率
            self.fs = self.wl_data['frequency_parameters']['amplifier_sample_rate']
            logger.info(f"采样频率: {self.fs} Hz")
            
            # 提取电生理数据
            if 'amplifier_data' in self.wl_data:
                self.amp_data = self.wl_data['amplifier_data']
                logger.info(f"电生理数据形状: {self.amp_data.shape}")
            else:
                logger.error("未找到电生理数据")
                return False
            
            # 提取数字输入数据
            if 'board_dig_in_data' in self.wl_data:
                self.dig_in_data = self.wl_data['board_dig_in_data']
                logger.info(f"数字输入数据形状: {self.dig_in_data.shape}")
            else:
                logger.error("未找到数字输入数据")
                return False
            
            # 提取或生成时间戳
            if 't_amplifier' in self.wl_data:
                self.time_stamps = self.wl_data['t_amplifier']
            else:
                num_samples = self.amp_data.shape[1]
                self.time_stamps = np.arange(num_samples) / self.fs
                logger.warning("时间戳不存在，已根据采样频率生成")
            
            logger.info(f"WL数据加载成功 - 数据长度: {len(self.time_stamps)} 样本点, "
                       f"时长: {len(self.time_stamps)/self.fs:.2f}秒")
            return True
            
        except Exception as e:
            logger.error(f"加载WL文件失败: {e}")
            return False


    def detect_markers(self) -> List[Dict[str, Any]]:
        """
        检测数字输入信号中的标记
        
        Returns:
            List[Dict]: 检测到的标记列表
        """
        if self.dig_in_data is None:
            if not self.load_data_file():
                return []
        
        logger.info("开始检测标记...")
        self.markers = []
        
        # 时间偏移设置
        first_marker_found = False
        original_first_time = None
        
        # 重构数字信号为整数值
        num_channels, num_samples = self.dig_in_data.shape
        dig_values = np.zeros(num_samples, dtype=np.int32)
        
        # 将布尔值通道合并为整数值
        for ch_idx in range(min(num_channels, 8)):  # 最多支持8个通道
            bit_position = ch_idx
            channel_data = self.dig_in_data[ch_idx, :].astype(np.int32)
            dig_values += channel_data * (1 << bit_position)
        
        # 检测上升沿
        previous_value = dig_values[0]
        
        for i in range(1, num_samples):
            current_value = dig_values[i]
            current_time = self.time_stamps[i]
            
            # 检测上升沿
            rising_edges = (previous_value ^ current_value) & current_value
            
            if rising_edges > 0:
                # 检查每个配置的通道
                for bit_value, channel_config in self.channel_configs.items():
                    if not channel_config.enabled:
                        continue
                    
                    if rising_edges & bit_value:  # 检查特定位是否置1
                        # 时间对齐处理
                        adjusted_time = current_time
                        if self.processing_config.alignment_time is not None:
                            if not first_marker_found:
                                original_first_time = current_time
                                first_marker_found = True
                            time_offset_from_first = current_time - original_first_time
                            adjusted_time = self.processing_config.alignment_time + time_offset_from_first
                        
                        # 构建标记信息
                        marker = {
                            'port': channel_config.name,
                            'port_bit': bit_value,
                            'start_time': adjusted_time,
                            'start_sample': i,
                            'duration': channel_config.duration,
                            'end_time': adjusted_time + channel_config.duration,
                            'end_sample': min(i + int(channel_config.duration * self.fs), num_samples - 1),
                            'description': channel_config.description
                        }
                        
                        # 保存原始时间（如果进行了时间调整）
                        if self.processing_config.alignment_time is not None:
                            marker['original_time'] = current_time
                        
                        self.markers.append(marker)
                        
                        # 日志记录
                        if self.processing_config.alignment_time is not None:
                            logger.info(f"检测到标记 - {channel_config.name}: "
                                       f"{adjusted_time:.3f}s (原始{current_time:.3f}s), "
                                       f"持续{channel_config.duration}s")
                        else:
                            logger.info(f"检测到标记 - {channel_config.name}: "
                                       f"{current_time:.3f}s, 持续{channel_config.duration}s")
            
            previous_value = current_value
        
        logger.info(f"共检测到 {len(self.markers)} 个标记")
        return self.markers
    
    def organize_data_by_paradigm(self) -> Dict[str, List[np.ndarray]]:
        """
        主调度方法，数据组织的核心调度器，它的作用是：
          1. 决定使用哪种数据分组策略
          2. 调用相应的子方法进行实际分组

        
        Returns:
            Dict[str, List[np.ndarray]]: 组织后的数据
        """
        if not self.markers:
            self.detect_markers()
        
        if not self.markers:
            logger.error("没有检测到标记，无法组织数据")
            return {}
        
        # 根据配置的范式类型选择组织方式
        effective_paradigm_type = self._get_effective_paradigm_type()
        
        # 根据范式类型选择处理方式
        if effective_paradigm_type == "corpus":
            return self._organize_by_corpus()
        elif effective_paradigm_type == "movement":
            return self._organize_by_movement()
        else:  # port 或其他情况
            return self._organize_by_port()
    
    def split_audio_by_markers(self) -> Dict[str, List[np.ndarray]]:
        """
        按照电生理数据的分割标记来分割音频
        
        Returns:
            Dict[str, List[np.ndarray]]: 分割后的音频数据，键为分组名称
        """
        if self.audio_data is None:
            logger.warning("没有加载音频数据，无法分割音频")
            return {}
        
        if not self.markers:
            self.detect_markers()
        
        if not self.markers:
            logger.error("没有检测到标记，无法分割音频")
            return {}
        
        logger.info("开始按照电生理标记分割音频...")
        
        # 根据范式类型选择分割方式
        effective_paradigm_type = self._get_effective_paradigm_type()
        
        if effective_paradigm_type == "corpus":
            return self._split_audio_by_corpus()
        elif effective_paradigm_type == "movement":
            return self._split_audio_by_movement()
        else:
            return self._split_audio_by_port()
    
    def _split_audio_by_port(self) -> Dict[str, List[np.ndarray]]:
        """按端口分割音频 - 只处理通道1的标记"""
        audio_segments = {}
        processed_count = 0
        
        for marker in self.markers:
            port = marker['port']
            start_time = marker['start_time']
            end_time = marker['end_time']
            
            # 只处理通道1的标记，因为音频只对应通道1
            if port == "通道1":
                # 计算音频的时间戳，需要在alignment_time基础上再加上audio_ahead
                audio_start_time = start_time + self.processing_config.audio_ahead
                audio_end_time = end_time + self.processing_config.audio_ahead
                
                # 计算音频的样本索引
                audio_start_sample = int(audio_start_time * self.audio_fs)
                audio_end_sample = int(audio_end_time * self.audio_fs)
                
                # 确保索引不超出音频数据范围
                audio_start_sample = max(0, audio_start_sample)
                audio_end_sample = min(len(self.audio_data), audio_end_sample)
                
                if audio_start_sample >= audio_end_sample:
                    logger.warning(f"音频分割范围无效: {start_time:.3f}s - {end_time:.3f}s")
                    continue
                
                # 提取音频段
                if len(self.audio_data.shape) == 1:  # 单声道
                    audio_segment = self.audio_data[audio_start_sample:audio_end_sample]
                else:  # 多声道
                    audio_segment = self.audio_data[audio_start_sample:audio_end_sample, :]
                
                if port not in audio_segments:
                    audio_segments[port] = []
                
                audio_segments[port].append(audio_segment)
                processed_count += 1
                logger.debug(f"添加{port}的音频段 (第{processed_count}个): {audio_start_time:.3f}s - {audio_end_time:.3f}s (电生理: {start_time:.3f}s - {end_time:.3f}s), 形状: {audio_segment.shape}")
        
        logger.info(f"端口模式音频分割完成: 共处理{processed_count}个通道1标记")
        return audio_segments
    
    def _split_audio_by_movement(self) -> Dict[str, List[np.ndarray]]:
        """按运动范式分割音频 - 只处理通道1的标记"""
        audio_segments = {}
        processed_count = 0
        
        for marker in self.markers:
            port = marker['port']
            start_time = marker['start_time']
            end_time = marker['end_time']
            
            # 只处理通道1的标记，因为音频只对应通道1
            if port == "通道1":
                # 使用与电生理数据相同的分组键逻辑
                group_key = self._get_movement_group_key(port, marker)
                
                # 计算音频的时间戳，需要在alignment_time基础上再加上audio_ahead
                audio_start_time = start_time + self.processing_config.audio_ahead
                audio_end_time = end_time + self.processing_config.audio_ahead
                
                # 计算音频的样本索引
                audio_start_sample = int(audio_start_time * self.audio_fs)
                audio_end_sample = int(audio_end_time * self.audio_fs)
                
                # 确保索引不超出音频数据范围
                audio_start_sample = max(0, audio_start_sample)
                audio_end_sample = min(len(self.audio_data), audio_end_sample)
                
                if audio_start_sample >= audio_end_sample:
                    logger.warning(f"音频分割范围无效: {start_time:.3f}s - {end_time:.3f}s")
                    continue
                
                # 提取音频段
                if len(self.audio_data.shape) == 1:  # 单声道
                    audio_segment = self.audio_data[audio_start_sample:audio_end_sample]
                else:  # 多声道
                    audio_segment = self.audio_data[audio_start_sample:audio_end_sample, :]
                
                if group_key not in audio_segments:
                    audio_segments[group_key] = []
                
                audio_segments[group_key].append(audio_segment)
                processed_count += 1
                logger.debug(f"添加'{group_key}'的音频段 (第{processed_count}个通道1标记): {audio_start_time:.3f}s - {audio_end_time:.3f}s (电生理: {start_time:.3f}s - {end_time:.3f}s), 形状: {audio_segment.shape}")
        
        logger.info(f"运动范式音频分割完成: 共处理{processed_count}个通道1标记")
        return audio_segments
    
    def _split_audio_by_corpus(self) -> Dict[str, List[np.ndarray]]:
        """按语料范式分割音频 - 只处理通道1的标记"""
        audio_segments = {}
        
        # 创建语料映射
        corpus_map = {item['order']: item['corpus'] for item in self.movement_data} if self.movement_data else {}
        
        # 只处理通道1的标记
        channel1_marker_count = 0
        
        for marker in self.markers:
            port = marker['port']
            start_time = marker['start_time']
            end_time = marker['end_time']
            
            # 只处理通道1的标记，因为音频只对应通道1
            if port == "通道1":
                channel1_marker_count += 1
                corpus_index = ((channel1_marker_count - 1) % len(corpus_map)) + 1
                corpus_text = corpus_map.get(corpus_index, f"语料{corpus_index}")
                segment_count = ((channel1_marker_count - 1) // len(corpus_map)) + 1
                group_key = f"语料{corpus_index:03d}_{corpus_text}_{segment_count:02d}"
                
                # 计算音频的时间戳，需要在alignment_time基础上再加上audio_ahead
                audio_start_time = start_time + self.processing_config.audio_ahead
                audio_end_time = end_time + self.processing_config.audio_ahead
                
                # 计算音频的样本索引
                audio_start_sample = int(audio_start_time * self.audio_fs)
                audio_end_sample = int(audio_end_time * self.audio_fs)
                
                # 确保索引不超出音频数据范围
                audio_start_sample = max(0, audio_start_sample)
                audio_end_sample = min(len(self.audio_data), audio_end_sample)
                
                if audio_start_sample >= audio_end_sample:
                    logger.warning(f"音频分割范围无效: {start_time:.3f}s - {end_time:.3f}s")
                    continue
                
                # 提取音频段
                if len(self.audio_data.shape) == 1:  # 单声道
                    audio_segment = self.audio_data[audio_start_sample:audio_end_sample]
                else:  # 多声道
                    audio_segment = self.audio_data[audio_start_sample:audio_end_sample, :]
                
                if group_key not in audio_segments:
                    audio_segments[group_key] = []
                
                audio_segments[group_key].append(audio_segment)
                logger.debug(f"添加'{group_key}'的音频段 (第{channel1_marker_count}个通道1标记): {audio_start_time:.3f}s - {audio_end_time:.3f}s (电生理: {start_time:.3f}s - {end_time:.3f}s), 形状: {audio_segment.shape}")
        
        logger.info(f"语料范式音频分割完成: 共处理{channel1_marker_count}个通道1标记，生成{len(audio_segments)}个音频分组")
        return audio_segments
    
    def _organize_by_port(self) -> Dict[str, List[np.ndarray]]:
        """没有CSV文件时的默认分组方式"""
        grouped_data = {}
        
        logger.info("未检测到CSV，按打标端口组织数据...")
        
        for marker in self.markers:
            port = marker['port']
            start_sample = marker['start_sample']
            end_sample = marker['end_sample']
            
            # 提取数据段
            segment_data = self.amp_data[:, start_sample:end_sample]
            
            if port not in grouped_data:
                grouped_data[port] = []
            
            grouped_data[port].append(segment_data)
            logger.debug(f"添加{port}的第{len(grouped_data[port])}段数据: {segment_data.shape}")
        
        # 打印摘要
        logger.info("=== 端口分组结果 ===")
        for port, segments in grouped_data.items():
            logger.info(f"{port}: {len(segments)}个数据段")
        
        return grouped_data
    
    def _organize_by_movement(self) -> Dict[str, List[np.ndarray]]:
        """按运动范式组织数据"""
        grouped_data = {}
        
        logger.info("按运动范式组织数据...")
        logger.info(f"运动范式条目: {len(self.movement_data)}个")
        
        for marker in self.markers:
            port = marker['port']
            start_sample = marker['start_sample']
            end_sample = marker['end_sample']
            
            segment_data = self.amp_data[:, start_sample:end_sample]
            
            # 根据端口名称确定分组逻辑
            group_key = self._get_movement_group_key(port, marker)
            
            if group_key not in grouped_data:
                grouped_data[group_key] = []
            
            grouped_data[group_key].append(segment_data)
            logger.debug(f"添加'{group_key}'的第{len(grouped_data[group_key])}段数据")
        
        # 打印摘要
        logger.info("=== 运动范式分组结果 ===")
        for group, segments in grouped_data.items():
            logger.info(f"{group}: {len(segments)}个试次")
        
        return grouped_data
    
    def _get_movement_group_key(self, port: str, marker: Dict) -> str:
        """
        根据端口和标记信息获取运动范式分组键
        
        Args:
            port: 端口名称
            marker: 标记信息
            
        Returns:
            str: 分组键
        """
        # 查找对应的通道配置
        channel_config = None
        for config in self.channel_configs.values():
            if config.name == port:
                channel_config = config
                break
        
        if not channel_config:
            return port  # fallback
        
        # 根据通道位值确定分组逻辑
        # 查找这个通道对应的bit_value
        channel_bit_value = None
        for bit_value, config in self.channel_configs.items():
            if config.name == port:
                channel_bit_value = bit_value
                break
        
        if channel_bit_value in [1, 2, 4]:  # 通道1,2,3 - 按动作分组
            # 计算当前是第几个该通道的标记
            current_marker_count = len([m for m in self.markers 
                                       if m['port'] == port and m['start_time'] <= marker['start_time']])
            action_num = ((current_marker_count - 1) % len(self.movement_data)) + 1
            
            # 根据通道位值确定阶段名称
            stage_map = {1: "准备", 2: "执行", 4: "复位"}
            stage = stage_map.get(channel_bit_value, "未知")
            
            return f"动作{action_num}_{stage}"
        else:
            # 其他通道直接使用端口名
            return port
    
    def _organize_by_corpus(self) -> Dict[str, List[np.ndarray]]:
        """按语料范式组织数据"""
        grouped_data = {}
        
        logger.info("按语料范式组织数据...")
        logger.info(f"语料范式条目: {len(self.movement_data)}个")
        
        # 为语料范式创建映射
        corpus_map = {item['order']: item['corpus'] for item in self.movement_data}
        
        # 按标记顺序处理所有标记
        channel1_marker_count = 0  # 用于跟踪通道1的标记数量，以确定对应的语料
        port_counters = {}  # 用于跟踪各通道的计数
        
        for marker in self.markers:
            port = marker['port']
            start_sample = marker['start_sample']
            end_sample = marker['end_sample']
            
            # 提取脑电数据段
            segment_data = self.amp_data[:, start_sample:end_sample]
            
            if port == "通道1":
                # 通道1使用语料命名
                channel1_marker_count += 1
                corpus_index = ((channel1_marker_count - 1) % len(corpus_map)) + 1
                corpus_text = corpus_map.get(corpus_index, f"语料{corpus_index}")
                # 计算该语料的出现次数（用作序号）
                segment_count = ((channel1_marker_count - 1) // len(corpus_map)) + 1
                group_key = f"语料{corpus_index:03d}_{corpus_text}_{segment_count:02d}"
            else:
                # 其他通道使用端口命名
                if port not in port_counters:
                    port_counters[port] = 0
                port_counters[port] += 1
                group_key = f"{port}_{port_counters[port]:03d}"
            
            if group_key not in grouped_data:
                grouped_data[group_key] = []
            
            grouped_data[group_key].append(segment_data)
            logger.debug(f"添加'{group_key}'的数据段: {segment_data.shape}")
        
        # 打印摘要
        logger.info("=== 语料范式分组结果 ===")
        for group, segments in grouped_data.items():
            logger.info(f"{group}: {len(segments)}个数据段")
        
        return grouped_data
    
    def _get_effective_paradigm_type(self) -> str:
        """
        获取有效的范式类型（解析auto模式）
        
        Returns:
            str: 实际使用的范式类型
        """
        paradigm_type = self.paradigm_type
        
        if paradigm_type == "auto":
            # auto模式下，如果有CSV文件则默认使用movement，否则使用port
            if self.file_config.csv_path and Path(self.file_config.csv_path).exists():
                return "movement"  # 默认假设为运动范式
            else:
                return "port"
        
        return paradigm_type

    def save_organized_segments(self, output_path: Optional[str] = None) -> str:
        """
        保存组织化的脑电数据段和音频数据段
        
        Args:
            output_path: 输出文件路径
            
        Returns:
            str: 保存的文件路径
        """
        grouped_data = self.organize_data_by_paradigm()
        
        if not grouped_data:
            logger.error("没有数据可保存")
            return ""
        
        # 分割音频数据
        audio_segments = {}
        if self.audio_data is not None:
            logger.info("正在分割音频数据...")
            audio_segments = self.split_audio_by_markers()
            logger.info(f"音频分割完成，共{len(audio_segments)}个分组")
        
        if output_path is None:
            base_filename = Path(self.file_config.data_path).stem
            output_dir = self.file_config.output_dir or Path(self.file_config.data_path).parent
            output_path = Path(output_dir) / f"{base_filename}_organized_segments.npy"
        
        # 创建完整的数据结构
        organized_data = {
            'grouped_data': grouped_data,
            'audio_segments': audio_segments,  # 添加音频分割数据
            'markers': self.markers,
            'fs': self.fs,
            'audio_fs': self.audio_fs,  # 添加音频采样率
            'audio_channels': self.audio_channels,  # 添加音频通道数
            'audio_sample_width': self.audio_sample_width,  # 添加音频位深
            'original_file': self.file_config.data_path,
            'original_audio_file': self.file_config.audio_path,  # 添加原始音频文件路径
            'channel_configs': {bit: {
                'name': config.name,
                'duration': config.duration,
                'description': config.description,
                'enabled': config.enabled
            } for bit, config in self.channel_configs.items()},
            'frequency_parameters': self.wl_data['frequency_parameters'] if self.wl_data else None,
            'movement_data': self.movement_data,
            'paradigm_type': self.paradigm_type,
            'data_type': self._get_effective_paradigm_type(),
            'processing_config': {
                'alignment_time': self.processing_config.alignment_time,
                'alignment_channel': self.processing_config.alignment_channel
            }
        }
        
        # 保存数据
        try:
            np.save(output_path, organized_data)
            logger.info(f"组织化的脑电数据段已保存: {output_path}")
            logger.info(f"数据包含组: {list(grouped_data.keys())}")
            if audio_segments:
                logger.info(f"音频数据分割组: {list(audio_segments.keys())}")
            return str(output_path)
        except Exception as e:
            logger.error(f"保存数据失败: {e}")
            return ""
    
    def get_processing_summary(self) -> Dict[str, Any]:
        """
        获取处理摘要信息
        
        Returns:
            Dict: 处理摘要
        """
        if not self.markers:
            self.detect_markers()
        
        # 按端口统计
        port_stats = {}
        total_duration = 0
        
        for marker in self.markers:
            port = marker['port']
            duration = marker['duration']
            
            if port not in port_stats:
                port_stats[port] = {'count': 0, 'total_duration': 0}
            
            port_stats[port]['count'] += 1
            port_stats[port]['total_duration'] += duration
            total_duration += duration
        
        return {
            'total_markers': len(self.markers),
            'total_duration': total_duration,
            'port_statistics': port_stats,
            'enabled_channels': len([c for c in self.channel_configs.values() if c.enabled]),
            'paradigm_type': self.paradigm_type,
            'data_type': self._get_effective_paradigm_type(),
            'has_audio': self.audio_data is not None,
            'sampling_rate': self.fs
        }

def process_data_file(config_path: str = "config.json") -> bool:
    """
    使用分割器处理数据文件（支持WL和PKL格式）
    
    Args:
        config_path: 配置文件路径
        
    Returns:
        bool: 是否处理成功
    """
    try:
        # 创建分割器
        logger.info("创建数据分割器...")
        splitter = WLDataSplitter(config_path)
        
        # 打印配置摘要
        splitter.config_manager.print_current_config()
        
        # 加载可选数据
        splitter.load_csv_data()
        splitter.load_audio_file()
        
        # 加载数据文件
        if not splitter.load_data_file():
            logger.error("无法加载数据文件")
            return False
        
        # 检测标记
        markers = splitter.detect_markers()
        if not markers:
            logger.error("未检测到任何标记")
            return False
        
        # 获取处理摘要
        summary = splitter.get_processing_summary()
        logger.info("=== 处理摘要 ===")
        logger.info(f"配置范式类型: {summary['paradigm_type']}")
        logger.info(f"实际处理类型: {summary['data_type']}")
        logger.info(f"总标记数: {summary['total_markers']}")
        logger.info(f"总持续时间: {summary['total_duration']:.2f}秒")
        logger.info(f"启用通道数: {summary['enabled_channels']}")
        logger.info(f"采样频率: {summary['sampling_rate']} Hz")
        
        for port, stats in summary['port_statistics'].items():
            logger.info(f"  {port}: {stats['count']}个标记, 总时长{stats['total_duration']:.2f}秒")
        
        # 保存组织化数据
        output_path = splitter.save_organized_segments()
        
        if output_path:
            logger.info("=== 处理完成 ===")
            logger.info(f"输出文件: {output_path}")
            
            # 自动保存音频分割段为WAV文件
            if splitter.audio_data is not None:
                logger.info("=== 保存音频分割段 ===")
                try:
                    from pathlib import Path
                    import wave
                    
                    # 设置音频输出目录
                    output_dir = Path(output_path).parent / "audio_segments"
                    output_dir.mkdir(exist_ok=True)
                    logger.info(f"音频输出目录: {output_dir}")
                    
                    # 获取音频分割数据
                    audio_segments = splitter.split_audio_by_markers()
                    if audio_segments:
                        saved_count = 0
                        for group_key, segments_list in audio_segments.items():
                            logger.info(f"处理分组 '{group_key}': {len(segments_list)}个片段")
                            
                            for idx, audio_segment in enumerate(segments_list):
                                # 生成文件名
                                if len(segments_list) == 1:
                                    filename = f"{group_key}.wav"
                                else:
                                    filename = f"{group_key}_{idx+1:02d}.wav"
                                
                                output_file = output_dir / filename
                                
                                try:
                                    # 保存wav文件
                                    with wave.open(str(output_file), 'wb') as wav_file:
                                        wav_file.setnchannels(splitter.audio_channels)
                                        wav_file.setsampwidth(splitter.audio_sample_width)
                                        wav_file.setframerate(splitter.audio_fs)
                                        
                                        # 转换数据类型
                                        if splitter.audio_sample_width == 1:
                                            audio_data = audio_segment.astype(np.uint8)
                                        elif splitter.audio_sample_width == 2:
                                            audio_data = audio_segment.astype(np.int16)
                                        elif splitter.audio_sample_width == 4:
                                            audio_data = audio_segment.astype(np.int32)
                                        else:
                                            logger.error(f"不支持的位深: {splitter.audio_sample_width*8}位")
                                            continue
                                        
                                        # 写入音频数据
                                        wav_file.writeframes(audio_data.tobytes())
                                        
                                    saved_count += 1
                                    duration = len(audio_segment) / splitter.audio_fs
                                    logger.info(f"保存音频: {filename} (时长: {duration:.3f}s)")
                                    
                                except Exception as e:
                                    logger.error(f"保存音频失败 {filename}: {e}")
                        
                        logger.info(f"音频分割完成，共保存 {saved_count} 个音频文件到: {output_dir}")
                    else:
                        logger.warning("没有音频分割段可保存")
                        
                except Exception as e:
                    logger.error(f"保存音频分割段时出错: {e}")
            else:
                logger.info("没有音频数据，跳过音频分割段保存")
            
            logger.info("使用 read_segments_demo.py 来读取分析数据")
            return True
        else:
            logger.error("保存数据失败")
            return False
        
    except Exception as e:
        logger.error(f"处理过程中发生错误: {e}")
        return False


def main():
    """主函数 - 使用优化的配置驱动处理"""
    print("=" * 60)
    print("优化的WL文件脑电数据分割器 v2.0")
    print("完全配置文件驱动，无硬编码参数")
    print("支持电生理数据和音频同步分割")
    print("=" * 60)
    
    config_path = "config.json"
    
    # 检查配置文件
    if not Path(config_path).exists():
        logger.error(f"配置文件不存在: {config_path}")
        logger.info("正在生成配置模板...")
        
        config_manager = ConfigManager()
        config_manager.generate_config_template(config_path)
        
        print(f"已生成配置模板: {config_path}")
        print("请编辑配置文件后重新运行程序")
        return
    
    try:
        # 处理文件
        success = process_data_file(config_path)
        
        if success:
            print("\n" + "=" * 60)
            print("处理成功完成！")
            print("=" * 60)
        else:
            print("\n" + "=" * 60) 
            print("处理失败，请查看日志了解详情")
            print("=" * 60)
    
    except KeyboardInterrupt:
        logger.info("用户中断处理")
    except Exception as e:
        logger.error(f"程序执行失败: {e}")

if __name__ == "__main__":
    main()